package middleware

import (
	"fmt"
	"gitee.com/xlizy/common-go/base/common_config"
	"gitee.com/xlizy/common-go/base/common_const"
	"gitee.com/xlizy/common-go/base/common_goroutine"
	"gitee.com/xlizy/common-go/base/enums/common_error"
	"gitee.com/xlizy/common-go/base/response"
	"gitee.com/xlizy/common-go/components/orm/tx"
	"gitee.com/xlizy/common-go/components/universal"
	"gitee.com/xlizy/common-go/utils/common_utils"
	rm "gitee.com/xlizy/common-go/utils/middleware/router_manage"
	"gitee.com/xlizy/common-go/utils/threadlocal"
	"gitee.com/xlizy/common-go/utils/zlog"
	"gitee.com/xlizy/rpc-interface/rpc_pbs"
	"github.com/google/uuid"
	"github.com/kataras/iris/v12/context"
	"runtime"
	"strings"
	"time"
)

// RouteLogHandler 路由打印
var RouteLogHandler = func(ctx *context.Context) {
	//zlog.Info("middleware Default")
	zlog.Info("MainHandlerName:{},router:{}", ctx.GetCurrentRoute().MainHandlerName(), ctx.RouteName())
	ctx.Next()
}

// SaveOpHandler 保存操作记录
var SaveOpHandler = func(ctx *context.Context) {
	//zlog.Info("middleware SaveOp")
	if lr, ok := rm.IrisRouterMap[ctx.RouteName()]; ok {
		if lr.SaveOp {
			req := &rpc_pbs.UserOperationBehaviorReq{
				UserId:       threadlocal.GetUserId(),
				ServerName:   common_config.GetAppName(),
				ApiPath:      ctx.RouteName(),
				EventCode:    ctx.GetCurrentRoute().MainHandlerName(),
				EventName:    rm.IrisRouterMap[ctx.RouteName()].Description,
				ExtendData:   "{}",
				Ipv4:         common_utils.RemoteIp(ctx.Request()),
				Ipv6:         "",
				Device:       "未知",
				UserAgent:    ctx.Request().UserAgent(),
				SomeId:       ctx.Request().Header.Get("X-Request-Some"),
				TraceId:      threadlocal.GetTraceId(),
				BehaviorTime: time.Now().Format(common_const.DataFormat),
			}
			traceId := threadlocal.GetTraceId()
			_ = common_goroutine.GetNonBlockingAntsPool().Submit(func() {
				threadlocal.SetTraceId(traceId)
				universal.SaveUserOperationBehavior(req)
			})
		}
	}
	ctx.Next()
}

// CrossDomainHandler 跨域设置(网关服务用)
var CrossDomainHandler = func(ctx *context.Context) {
	//zlog.Info("middleware CrossDomain")
	ctx.Header("Access-Control-Allow-Origin", ctx.Request().Header.Get("Origin"))
	ctx.Header("Access-Control-Allow-Headers", "Content-Type,Content-Disposition,X-Request-Id,X-Request-Some")
	ctx.Header("Access-Control-Expose-Headers", "Content-Length,Access-Control-Allow-Origin,Access-Control-Allow-Headers,Content-Type,cache-control,Set-Auth,Content-Disposition")
	ctx.Header("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE,PATCH,HEAD,TRACE")
	ctx.Header("Access-Control-Allow-Credentials", "true")
	ctx.Header("Access-Control-Max-Age", "7200")
	if ctx.Request().Method == "OPTIONS" {
		ctx.StatusCode(200)
	} else {
		ctx.Next()
	}
}

// NeedLogin 拦截器-需要登录(具体路由使用)
var NeedLogin = func(ctx *context.Context) {
	//zlog.Info("middleware NeedLogin")
	userId := ctx.GetHeader("X-Request-UserId")
	if userId == "" {
		_ = ctx.JSON(response.Error(common_error.NotLoggedIn, nil))
	} else {
		if userId != "" {
			threadlocal.SetUserId(userId)
			ctx.Next()
		} else {
			_ = ctx.JSON(response.Error(common_error.NotLoggedIn, nil))
		}
	}
}

// GlobalRouterHandler 全局路由处理方法
var GlobalRouterHandler = func(ctx *context.Context) {
	//zlog.Info("middleware GlobalRecover")

	//清除数据库事务记录(http连接可能被复用，每次请求进来清一下)
	tx.Clear()

	//设置请求跟踪ID
	traceId := ctx.GetHeader("X-Request-Id")
	if traceId == "" {
		traceId = uuid.New().String()
	}
	threadlocal.SetTraceId(traceId)
	//设置用户ID
	userId := ctx.GetHeader("X-Request-UserId")
	if userId != "" {
		threadlocal.SetUserId(userId)
	}

	//全局异常处理
	defer func() {
		if err := recover(); err != nil {
			if ctx.IsStopped() {
				return
			}

			if tx.IsInTX() {
				tx.NeedRollback()
				tx.TryCommit()
			}

			var stacktrace string
			for i := 1; ; i++ {
				_, f, l, got := runtime.Caller(i)
				if !got {
					break
				}
				stacktrace += fmt.Sprintf("%s:%d\n", f, l)
			}

			errMsg := fmt.Sprintf("%s", err)
			zlog.Info("异常Ctl入口:{}", ctx.HandlerName())
			zlog.Error("ErrorInfo:{}", errMsg)
			// 返回错误信息
			if strings.HasPrefix(errMsg, "") {
				_ = ctx.JSON(response.Error(common_error.SystemError, errMsg))
			}
			ctx.StatusCode(500)
			ctx.StopExecution()
		}
	}()

	ctx.Next()

	//请求结束后提交事务
	if tx.IsInTX() {
		tx.TryCommit()
	}
}
